/************************************************************************
This file is part of Polar4linux
Copyright (C) 2010-2011 Eric jrdn2
Portions Copyright (C) 2007 Matti Juvonen <mpj@iki.fi> (RS400 Tools)
Portions Copyright (C) 2006 Jani Hursti <jani.hursti@hut.fi>,
Portions Copyright (C) 2001-2003 Tom Oliveira e Silva

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
************************************************************************/

#include <stdio.h>
#include <math.h>
#include "RS400_util.h"

/* TODO: Which one of these is correct */

#ifdef RS400_CHARSET_ALT
static const char rs400_charset[] =
    "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?:./*-+%()";
#else
static const char rs400_charset[] =
    "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-%/()*+.:?";
#endif

//Decode from Polar's character set.
//Returns the length of the string.
//original code
int rs400_decode_string(unsigned char result[], const unsigned char rawdata[])
{
	int i = 0;
	do
	{
		/* The top bit signals the last byte */
		result[i] = rs400_charset[rawdata[i] & 0x7f];
	} while (!(rawdata[i++] & 0x80));
	result[i + 1] = '\0';          /* Terminate string */
	return (i + 1);
}

//same as original but stops at maxsize if 0x80 is not found
//result[] must be of size maxsize+1 in order to add '\0' at its end
int rs400_decode_string(unsigned char result[], const unsigned char rawdata[], unsigned int maxsize)
{
	unsigned int i=0;
	for (; i<maxsize;i++)
	{
		result[i] = rs400_charset[rawdata[i] & 0x7f];
		if (rawdata[i] & 0x80) break;
	}
		result[i+1]='\0';
		return maxsize;
}

//Decode from Polar's character set.
//debug version that _ignores_ Polar's end of string (for mass conversion)
//result[] must be of size size+1 in order to add '\0' at its end
int rs400_decode_stringDebug(unsigned char result[], const unsigned char rawdata[], unsigned int maxsize)
{
	for (unsigned i=0; i<maxsize;i++)
	{
		result[i] = rs400_charset[rawdata[i] & 0x7f];
	}
	result[maxsize]='\0';
	return maxsize;
}

/* Encode to Polar's character set.
This is really slow but it's not really a problem.
Returns the length of the string. */
int rs400_encode_string(unsigned char result[], const unsigned char string[]) {
	unsigned int i;
	for (i = 0; string[i] != '\0'; i++)
	{
		unsigned int j;
		for (j = 0; j < (sizeof(rs400_charset) / sizeof(char)); j++)
		{
			if (string[i] == rs400_charset[j])
			{
				result[i] = j;
				break;
			}
		}
	}
	result[i]+=0x80;
	return i;
}


//Encode to Polar's character set.
//string is a [maxsize+1] null terminated string
int rs400_encode_string(unsigned char result[], const unsigned char string[],unsigned int maxsize)
{
	unsigned int i;
	for (i = 0; i<maxsize; i++)
	{
		unsigned int j;
		for (j = 0; j < (sizeof(rs400_charset) / sizeof(char)); j++)
		{
			if (string[i] == rs400_charset[j])
			{
				result[i] = j;
				break;
			}
		}
	}
	result[maxsize-1]+=0x80;
	return i;
}

void displaybuf(unsigned char *buf,unsigned int size)
{
	unsigned char decodedS[9];
 	for (unsigned int i=0;i<size;i+=8)
 	{
		rs400_decode_stringDebug(decodedS, &buf[i],8);
		for (unsigned int j=0;j<8;j++) printf("%2x ",buf[i+j]);
		printf("\t");
		for (unsigned int j=0;j<8;j++) printf("%c ",decodedS[j]);
		printf("\n");
 	}
	printf("\n");
}

/* Convert from binary coded decimal */
unsigned int bcd2i(int bcd) {
    return ((bcd >> 4) * 10 + (bcd & 0x0f));
}

double hms2sec(unsigned char h, unsigned char m, unsigned char s) {
    /* Horner rules */
    return (((h * 60) + m) * 60) + s;
}

double hmst2sec(unsigned char h, unsigned char m, unsigned char s, unsigned char t) {
    return ((((h * 60) + m) * 60) + s) + (0.1 * t);
}

double hmsc2sec(unsigned char h, unsigned char m, unsigned char s, unsigned char c) {
    return ((((h * 60) + m) * 60) + s) + (0.01 * c);
}

double bcd_hms2sec(const unsigned char pos[]) {
    unsigned char h = bcd2i(pos[2]);
    unsigned char m = bcd2i(pos[1]);
    unsigned char s = bcd2i(pos[0]);
    return hms2sec(h, m, s);
}

double bcd_hmsc2sec(const unsigned char pos[]) {
    unsigned char h = bcd2i(pos[3]);
    unsigned char m = bcd2i(pos[2]);
    unsigned char s = bcd2i(pos[1]);
    unsigned char c = bcd2i(pos[0]);
    return hmsc2sec(h, m, s, c);
}

double short2sec(const unsigned char pos[]) {
    unsigned char hours = pos[2] & 0x7f;
    unsigned char minutes = pos[1] & 0x3f;
    unsigned char seconds = pos[0] & 0x3f;
    /* We can just fit the tents in the extra bits */
    unsigned char tenths = ((pos[1] & 0xc0) >> 4) | ((pos[0] & 0xc0) >> 6);
    return hmst2sec(hours, minutes, seconds, tenths);
}

unsigned short toshort(const unsigned char pos[]) {
    return ((pos[1] << 8) | pos[0]);
}

unsigned int pace(unsigned char pos[]) {
    int sixteenths = ((pos[1] & 0xf0) << 2) + pos[0];
    return sixteenths * 600.0 / 16.0;
}

void timetostr(char str[], double time) {
    unsigned int inttime = time;
    unsigned int tenths = round((time - inttime) * 10.0);
    unsigned int hours = inttime / 3600;
    inttime %= 3600;
    unsigned int minutes = inttime / 60;
    inttime %= 60;
    unsigned int seconds = inttime;
    sprintf(str, "%02d:%02d:%02d.%d", hours, minutes, seconds, tenths);
}

void hmstostr(char str[], int h, int m, int s, char sep) {
    sprintf(str, "%02d%c%02d%c%02d", h, sep, m, sep, s);
}

/* ------------------------------------------------------------------------------------------------------
   Converts a number given as two bytes (high and low) into a single integer
--------------------------------------------------------------------------------------------------------- */
int msb_lsb_to_decimal(int msb, int lsb)
{
	return (lsb + (msb << 8));
}

int msb_lsb_to_weighKG(int msb, int lsb) //weigh en kilos
{
	int result = (int)((double)msb_lsb_to_decimal(lsb, msb)/10*0.45359+0.5);
	return result;
}

int msb_lsb_to_weighLB(int msb, int lsb) //weigh en lbs
{
	int result = (int)((double)msb_lsb_to_decimal(lsb, msb)/10);
	return result;
}


void int_to_msb_lsb(int dec, unsigned char* msb, unsigned char* lsb)
{
	unsigned char  b = dec >> 8;
	unsigned char  a = dec - (b <<8);

	*msb = b;
	*lsb = a;
}


void weighLB_to_msb_lsb(int dec, unsigned char* msb, unsigned char* lsb)
{
	dec*=10;
	int_to_msb_lsb(dec,msb,lsb);
}

void weighKG_to_msb_lsb(int dec, unsigned char* msb, unsigned char* lsb)
{
	int weighLB = 22*dec;
	int_to_msb_lsb(weighLB,msb,lsb);
}


int hexa_to_same_decimal(int hex) //if hex=0x42, then return is 42 (decimal base)
{
	int val1X = hex; //hexa value
	int val1I=0; //computed decimal values.

	int valX[]={0x1000,0x100,0x10,0x1};
	int valI[]={1000,100,10,1};

	int i;
	for (i=0;i<4;i++)
	{
		int tmp1 = val1X/valX[i];
		//printf("tmp1 %d\n",tmp1);
		val1I+=tmp1*valI[i];
		val1X-=tmp1*valX[i];
	}
	//printf("iohexa_to_same_decimal: %x %d \n",hex,val1I);
	return val1I;
}

int decimal_to_same_hexa(int decimal) //if hex=0x42, then return is 42 (decimal base)
{
	int val1I = decimal; //decimal value
	int val1X=0; //computed hexa values.

	int valX[]={0x1000,0x100,0x10,0x1};
	int valI[]={1000,100,10,1};
	int i;
	for (i=0;i<4;i++)
	{
		int tmp1 = val1I/valI[i];
		val1X+=tmp1*valX[i];
		val1I-=tmp1*valI[i];
	}
	return val1X;
}

void hex2ddmmyy(unsigned char hex0,unsigned char hex1,unsigned char *dd,unsigned char *mm, unsigned char *yy)
{
	unsigned char dd0,mm0,yy0;
	dd0=0;
	mm0=0;
	yy0=0;

	dd0=hex0%0x20; //the result is the decimal value we search.no need to convert
	mm0+=hex0/0x20;
	if (hex1%2!=0) mm0=mm0+8;
	//mm0+=hex1/0x02;
	yy0=hex1/0x02;
*dd=dd0;
*mm=mm0; //hexa_to_same_decimal(mm0);
*yy=yy0; //hexa_to_same_decimal(yy0);
//printf("initial %x %x decode %d %d %d\n",hex0,hex1,*dd,*mm,*yy);

}

void ddmmyy2hex(unsigned char dd,unsigned char mm, unsigned char yy,unsigned char *hex0,unsigned char *hex1)
{
*hex1 = yy*2;
if (mm>=8)
{
	*hex1=*hex1+1;
	mm=mm-8;}
;

*hex0 = dd+mm*0x20; //dd;// + tmp*0x20;
}




void RS400_reset_session(rs400_session *session)
{
	session->sample.clear();
	session->lap.clear();
	session->selections.clear();
	session->number_of_laps=0;
	session->number_of_samples=0;
}




float compute_Kcal(float PCfc,int weight,int vo2)
{
	float cal0=0;
	if (PCfc<0.9 && PCfc>0.5)
	{
		cal0 = -0.1306+PCfc*0.421;
	}
	else if (PCfc>=0.9)
	{
		cal0 = -0.2856+PCfc*0.595;
	}
	return cal0*weight*vo2/3600.0;
}




void _initialize_pdd(rs400_pdd_content &info, int day, int month, int year0)
{
	info.reset();

	int year;
	if (year0<100) year=2000+year0;
	else year=year0;

	info.dayinfo.fileVersionDAY=100;
	info.dayinfo.nbrInfoRowsDAY=1;
	info.dayinfo.nbrNumRowsDAY=7;
	info.dayinfo.nbrNumColumnsDAY=6;
	info.dayinfo.nbrTextRowsDAY=1;
	info.dayinfo.maxCharPerTextRowDAY=512;
	info.dayinfo.date=day+month*100+year*10000;
	info.dayinfo.nbrExercises=0;
	info.dayinfo.restingHR=0;
	info.dayinfo.orthoHR=0;
	info.dayinfo.weight=0;
	info.dayinfo.sleepingHours=0;
}

//computes laptimes for each lap, given lap_end_time
void compute_laptimes(rs400_session &session)
{
	session.lap[0].laptime=session.lap[0].lap_end_time;
	for (unsigned int i=1;i<session.lap.size();i++)
	{
		session.lap[i].laptime=session.lap[i].lap_end_time-session.lap[i-1].lap_end_time;
	}
}

